#pragma once

#include "Uvls.h"

using namespace System;
using namespace System::Text;
using namespace System::Runtime::InteropServices;
using namespace SbCli;

namespace SbCli
{
	namespace Qgp
	{
		//////////////////////////////////////////////////////////////////////////
		public ref class ResourceObj : RoamObject
		{
			DEFCLASS(ResourceObj, RoamObject, qgObj);

		public:
			ResourceObj(IntPtr handle)
				: super_type(handle)
			{
			}
		};


		//////////////////////////////////////////////////////////////////////////
		[StructLayout(LayoutKind::Sequential)]
		[Serializable]
		public value struct RaszData
		{
		public:
			TriangleFill Fill;
			CullMode Cull;

			float DepthBias;
			float SlopeScale;
		};

		public ref class RaszInitializer
		{
		internal:
			RaszData Data;

		public:
			RaszInitializer(TriangleFill fill, CullMode cull, float dbias, float slsl)
			{
				Data.Fill = fill;
				Data.Cull = cull;
				Data.DepthBias = dbias;
				Data.SlopeScale = slsl;
			}

			RaszInitializer(TriangleFill fill, CullMode cull)
			{
				Data.Fill = fill;
				Data.Cull = cull;
				Data.DepthBias = 0.0f;
				Data.SlopeScale = 0.0f;
			}

			RaszInitializer(TriangleFill fill)
			{
				Data.Fill = fill;
				Data.Cull = CullMode::None;
				Data.DepthBias = 0.0f;
				Data.SlopeScale = 0.0f;
			}

			RaszInitializer()
			{
				Data.Fill = TriangleFill::Solid;
				Data.Cull = CullMode::None;
				Data.DepthBias = 0.0f;
				Data.SlopeScale = 0.0f;
			}
		};

		public ref class RaszState : ResourceObj
		{
			DEFCLASS(RaszState, ResourceObj, qgRaszState);

		public:
			RaszState(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			RaszData GetData()
			{
				const qbRaszData& u = SELF->GetData();

				RaszData d;
				d.Fill = (TriangleFill)u.fill;
				d.Cull = (CullMode)u.cull;
				d.DepthBias = u.depth_bias;
				d.SlopeScale = u.slope_scale;

				return d;
			}
		};


		//////////////////////////////////////////////////////////////////////////
		[StructLayout(LayoutKind::Sequential)]
		[Serializable]
		public value struct BlndData
		{
		public:
			BlendOp ColorOp;
			BlendFactor ColorSource;
			BlendFactor ColorDest;

			BlendOp AlphaOp;
			BlendFactor AlphaSource;
			BlendFactor AlphaDest;

			ColorMask Mask;
		};

		public ref class BlndInitializer
		{
		internal:
			bool UseIndependent;
			array<BlndData>^ Data = gcnew array<BlndData>(QGSGOFF_MAX_VALUE);

		public:
			BlndInitializer(
				ColorMask r0mask, BlendOp r0cop, BlendFactor r0csrc, BlendFactor r0cdest, BlendOp r0aop, BlendFactor r0asrc, BlendFactor r0adest,
				ColorMask r1mask, BlendOp r1cop, BlendFactor r1csrc, BlendFactor r1cdest, BlendOp r1aop, BlendFactor r1asrc, BlendFactor r1adest,
				ColorMask r2mask, BlendOp r2cop, BlendFactor r2csrc, BlendFactor r2cdest, BlendOp r2aop, BlendFactor r2asrc, BlendFactor r2adest,
				ColorMask r3mask, BlendOp r3cop, BlendFactor r3csrc, BlendFactor r3cdest, BlendOp r3aop, BlendFactor r3asrc, BlendFactor r3adest)
			{
				Data[0].Mask = r0mask;
				Data[0].ColorOp = r0cop;
				Data[0].ColorSource = r0csrc;
				Data[0].ColorDest = r0cdest;
				Data[0].AlphaOp = r0aop;
				Data[0].AlphaSource = r0asrc;
				Data[0].AlphaDest = r0adest;
				//
				Data[1].Mask = r1mask;
				Data[1].ColorOp = r1cop;
				Data[1].ColorSource = r1csrc;
				Data[1].ColorDest = r1cdest;
				Data[1].AlphaOp = r1aop;
				Data[1].AlphaSource = r1asrc;
				Data[1].AlphaDest = r1adest;
				//
				Data[2].Mask = r2mask;
				Data[2].ColorOp = r2cop;
				Data[2].ColorSource = r2csrc;
				Data[2].ColorDest = r2cdest;
				Data[2].AlphaOp = r2aop;
				Data[2].AlphaSource = r2asrc;
				Data[2].AlphaDest = r2adest;
				//
				Data[3].Mask = r3mask;
				Data[3].ColorOp = r3cop;
				Data[3].ColorSource = r3csrc;
				Data[3].ColorDest = r3cdest;
				Data[3].AlphaOp = r3aop;
				Data[3].AlphaSource = r3asrc;
				Data[3].AlphaDest = r3adest;
				//
				UseIndependent = true;
			}

			BlndInitializer(ColorMask r0mask, BlendOp r0cop, BlendFactor r0csrc, BlendFactor r0cdest, BlendOp r0aop, BlendFactor r0asrc, BlendFactor r0adest)
			{
				Data[0].Mask = r0mask;
				Data[0].ColorOp = r0cop;
				Data[0].ColorSource = r0csrc;
				Data[0].ColorDest = r0cdest;
				Data[0].AlphaOp = r0aop;
				Data[0].AlphaSource = r0asrc;
				Data[0].AlphaDest = r0adest;
				//
				Data[1].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[1].ColorOp = BlendOp::Add;
				Data[1].ColorSource = BlendFactor::One;
				Data[1].ColorDest = BlendFactor::Zero;
				Data[1].AlphaOp = BlendOp::Add;
				Data[1].AlphaSource = BlendFactor::One;
				Data[1].AlphaDest = BlendFactor::Zero;
				//
				Data[2].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[2].ColorOp = BlendOp::Add;
				Data[2].ColorSource = BlendFactor::One;
				Data[2].ColorDest = BlendFactor::Zero;
				Data[2].AlphaOp = BlendOp::Add;
				Data[2].AlphaSource = BlendFactor::One;
				Data[2].AlphaDest = BlendFactor::Zero;
				//
				Data[3].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[3].ColorOp = BlendOp::Add;
				Data[3].ColorSource = BlendFactor::One;
				Data[3].ColorDest = BlendFactor::Zero;
				Data[3].AlphaOp = BlendOp::Add;
				Data[3].AlphaSource = BlendFactor::One;
				Data[3].AlphaDest = BlendFactor::Zero;
				//
				UseIndependent = false;
			}

			BlndInitializer(BlndData data)
			{
				Data[0] = data;
				//
				Data[1].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[1].ColorOp = BlendOp::Add;
				Data[1].ColorSource = BlendFactor::One;
				Data[1].ColorDest = BlendFactor::Zero;
				Data[1].AlphaOp = BlendOp::Add;
				Data[1].AlphaSource = BlendFactor::One;
				Data[1].AlphaDest = BlendFactor::Zero;
				//
				Data[2].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[2].ColorOp = BlendOp::Add;
				Data[2].ColorSource = BlendFactor::One;
				Data[2].ColorDest = BlendFactor::Zero;
				Data[2].AlphaOp = BlendOp::Add;
				Data[2].AlphaSource = BlendFactor::One;
				Data[2].AlphaDest = BlendFactor::Zero;
				//
				Data[3].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[3].ColorOp = BlendOp::Add;
				Data[3].ColorSource = BlendFactor::One;
				Data[3].ColorDest = BlendFactor::Zero;
				Data[3].AlphaOp = BlendOp::Add;
				Data[3].AlphaSource = BlendFactor::One;
				Data[3].AlphaDest = BlendFactor::Zero;
				//
				UseIndependent = false;
			}

			BlndInitializer()
			{
				Data[0].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[0].ColorOp = BlendOp::Add;
				Data[0].ColorSource = BlendFactor::One;
				Data[0].ColorDest = BlendFactor::Zero;
				Data[0].AlphaOp = BlendOp::Add;
				Data[0].AlphaSource = BlendFactor::One;
				Data[0].AlphaDest = BlendFactor::Zero;
				//
				Data[1].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[1].ColorOp = BlendOp::Add;
				Data[1].ColorSource = BlendFactor::One;
				Data[1].ColorDest = BlendFactor::Zero;
				Data[1].AlphaOp = BlendOp::Add;
				Data[1].AlphaSource = BlendFactor::One;
				Data[1].AlphaDest = BlendFactor::Zero;
				//
				Data[2].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[2].ColorOp = BlendOp::Add;
				Data[2].ColorSource = BlendFactor::One;
				Data[2].ColorDest = BlendFactor::Zero;
				Data[2].AlphaOp = BlendOp::Add;
				Data[2].AlphaSource = BlendFactor::One;
				Data[2].AlphaDest = BlendFactor::Zero;
				//
				Data[3].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
				Data[3].ColorOp = BlendOp::Add;
				Data[3].ColorSource = BlendFactor::One;
				Data[3].ColorDest = BlendFactor::Zero;
				Data[3].AlphaOp = BlendOp::Add;
				Data[3].AlphaSource = BlendFactor::One;
				Data[3].AlphaDest = BlendFactor::Zero;
				//
				UseIndependent = false;
			}

			BlndInitializer(array<BlndData>^ ads)
			{
				int count = K_MIN(ads->Length, 4);

				for (int i = 0; i < count; i++)
					Data[i] = ads[i];

				for (int i = count; i < QGSGOFF_MAX_VALUE; i++)
				{
					Data[i].Mask = ColorMask::Red | ColorMask::Green | ColorMask::Blue | ColorMask::Alpha;
					Data[i].ColorOp = BlendOp::Add;
					Data[i].ColorSource = BlendFactor::One;
					Data[i].ColorDest = BlendFactor::Zero;
					Data[i].AlphaOp = BlendOp::Add;
					Data[i].AlphaSource = BlendFactor::One;
					Data[i].AlphaDest = BlendFactor::Zero;
				}

				UseIndependent = count > 1;
			}
		};

		public ref class BlndState : ResourceObj
		{
			DEFCLASS(BlndState, ResourceObj, qgBlndState);

		public:
			BlndState(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			BlndData GetData()
			{
				const qbBlndData& u = SELF->GetData();

				BlndData d;
				d.ColorOp = (BlendOp)u.color_op;
				d.ColorSource = (BlendFactor)u.color_src;
				d.ColorDest = (BlendFactor)u.color_dest;
				d.AlphaOp = (BlendOp)u.alpha_op;
				d.AlphaSource = (BlendFactor)u.alpha_src;
				d.AlphaDest = (BlendFactor)u.alpha_dest;
				d.Mask = (ColorMask)u.mask;

				return d;
			}
		};


		//////////////////////////////////////////////////////////////////////////
		[StructLayout(LayoutKind::Sequential)]
		[Serializable]
		public value struct SplrData
		{
		public:
			TextureFilter Filter;
			TextureAddress AddrU;
			TextureAddress AddrV;
			TextureAddress AddrW;
			CompareOp Op;
			ColorValue BorderColor;
			int LodBias;
			float LodMin;
			float LoadMax;
		};

		public ref class SplrInitializer
		{
		internal:
			SplrData Data;

		public:
			SplrInitializer(TextureFilter filt, TextureAddress addru, TextureAddress addrv, TextureAddress addrw, int lbias, CompareOp op)
			{
				Data.Filter = filt;
				Data.AddrU = addru;
				Data.AddrV = addrv;
				Data.AddrW = addrw;
				Data.Op = op;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = lbias;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}

			SplrInitializer(TextureFilter filt, TextureAddress addru, TextureAddress addrv, TextureAddress addrw, int lbias)
			{
				Data.Filter = filt;
				Data.AddrU = addru;
				Data.AddrV = addrv;
				Data.AddrW = addrw;
				Data.Op = CompareOp::Never;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = lbias;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}

			SplrInitializer(TextureFilter filt, TextureAddress addru, TextureAddress addrv, TextureAddress addrw)
			{
				Data.Filter = filt;
				Data.AddrU = addru;
				Data.AddrV = addrv;
				Data.AddrW = addrw;
				Data.Op = CompareOp::Never;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = 0;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}

			SplrInitializer(TextureFilter filt, TextureAddress addr)
			{
				Data.Filter = filt;
				Data.AddrU = addr;
				Data.AddrV = addr;
				Data.AddrW = addr;
				Data.Op = CompareOp::Never;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = 0;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}

			SplrInitializer(TextureFilter filt)
			{
				Data.Filter = filt;
				Data.AddrU = TextureAddress::Clamp;
				Data.AddrV = TextureAddress::Clamp;
				Data.AddrW = TextureAddress::Clamp;
				Data.Op = CompareOp::Never;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = 0;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}

			SplrInitializer()
			{
				Data.Filter = TextureFilter::Point;
				Data.AddrU = TextureAddress::Clamp;
				Data.AddrV = TextureAddress::Clamp;
				Data.AddrW = TextureAddress::Clamp;
				Data.Op = CompareOp::Never;
				Data.BorderColor = ColorValues::Transparent;
				Data.LodBias = 0;
				Data.LodMin = 0.0f;
				Data.LoadMax = FLT_MAX;
			}
		};

		public ref class SplrState : ResourceObj
		{
			DEFCLASS(SplrState, ResourceObj, qgSplrState);

		public:
			SplrState(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			SplrData GetData()
			{
				const qbSplrData& u = SELF->GetData();

				SplrData d;
				d.Filter = (TextureFilter)u.filt;
				d.AddrU = (TextureAddress)u.addru;
				d.AddrV = (TextureAddress)u.addrv;
				d.AddrW = (TextureAddress)u.addrw;
				d.Op = (CompareOp)u.cop;
				d.BorderColor = (ColorValue&)u.bcv;
				d.LodBias = u.lod_bias;
				d.LodMin = u.lod_range.min;
				d.LoadMax = u.lod_range.max;

				return d;
			}
		};


		//////////////////////////////////////////////////////////////////////////
		[StructLayout(LayoutKind::Sequential)]
		[Serializable]
		public value struct DhslData
		{
		public:
			bool DepthWrite;
			CompareOp DepthFunc;

			bool FrontEnable;
			CompareOp FrontFunc;
			StencilOp FrontPass;
			StencilOp FrontFail;
			StencilOp FrontDepthFail;

			bool BackEnable;
			CompareOp BackFunc;
			StencilOp BackPass;
			StencilOp BackFail;
			StencilOp BackDepthFail;

			kbyte MaskRead;
			kbyte MaskWrite;
		};

		public ref class DhslInitializer
		{
		internal:
			DhslData Data;

		public:
			DhslInitializer(
				bool depth_write, CompareOp depth_func,
				bool front_enable, CompareOp front_func, StencilOp front_pass, StencilOp front_fail, StencilOp front_depth_fail,
				bool back_enable, CompareOp back_func, StencilOp back_pass, StencilOp back_fail, StencilOp back_depth_fail,
				kbyte mask_read, kbyte mask_write)
			{
				Data.DepthWrite = depth_write;
				Data.DepthFunc = depth_func;
				Data.FrontEnable = front_enable;
				Data.FrontFunc = front_func;
				Data.FrontPass = front_pass;
				Data.FrontFail = front_fail;
				Data.FrontDepthFail = front_depth_fail;
				Data.BackEnable = back_enable;
				Data.BackFunc = back_func;
				Data.BackPass = back_pass;
				Data.BackFail = back_fail;
				Data.BackDepthFail = back_depth_fail;
				Data.MaskRead = mask_read;
				Data.MaskWrite = mask_write;
			}

			DhslInitializer(
				bool depth_write, CompareOp depth_func,
				bool front_enable, CompareOp front_func, StencilOp front_pass, StencilOp front_fail, StencilOp front_depth_fail,
				bool back_enable, CompareOp back_func, StencilOp back_pass, StencilOp back_fail, StencilOp back_depth_fail)
			{
				Data.DepthWrite = depth_write;
				Data.DepthFunc = depth_func;
				Data.FrontEnable = front_enable;
				Data.FrontFunc = front_func;
				Data.FrontPass = front_pass;
				Data.FrontFail = front_fail;
				Data.FrontDepthFail = front_depth_fail;
				Data.BackEnable = back_enable;
				Data.BackFunc = back_func;
				Data.BackPass = back_pass;
				Data.BackFail = back_fail;
				Data.BackDepthFail = back_depth_fail;
				Data.MaskRead = 0xFF;
				Data.MaskWrite = 0xFF;
			}

			DhslInitializer(
				bool depth_write, CompareOp depth_func,
				bool front_enable, CompareOp front_func, StencilOp front_pass, StencilOp front_fail, StencilOp front_depth_fail)
			{
				Data.DepthWrite = depth_write;
				Data.DepthFunc = depth_func;
				Data.FrontEnable = front_enable;
				Data.FrontFunc = front_func;
				Data.FrontPass = front_pass;
				Data.FrontFail = front_fail;
				Data.FrontDepthFail = front_depth_fail;
				Data.BackEnable = false;
				Data.BackFunc = CompareOp::Always;
				Data.BackPass = StencilOp::Keep;
				Data.BackFail = StencilOp::Keep;
				Data.BackDepthFail = StencilOp::Keep;
				Data.MaskRead = 0xFF;
				Data.MaskWrite = 0xFF;
			}

			DhslInitializer(bool depth_write, CompareOp depth_func)
			{
				Data.DepthWrite = depth_write;
				Data.DepthFunc = depth_func;
				Data.FrontEnable = false;
				Data.FrontFunc = CompareOp::Always;
				Data.FrontPass = StencilOp::Keep;
				Data.FrontFail = StencilOp::Keep;
				Data.FrontDepthFail = StencilOp::Keep;
				Data.BackEnable = false;
				Data.BackFunc = CompareOp::Always;
				Data.BackPass = StencilOp::Keep;
				Data.BackFail = StencilOp::Keep;
				Data.BackDepthFail = StencilOp::Keep;
				Data.MaskRead = 0xFF;
				Data.MaskWrite = 0xFF;
			}

			DhslInitializer(bool depth_write)
			{
				Data.DepthWrite = depth_write;
				Data.DepthFunc = CompareOp::LEQ;
				Data.FrontEnable = false;
				Data.FrontFunc = CompareOp::Always;
				Data.FrontPass = StencilOp::Keep;
				Data.FrontFail = StencilOp::Keep;
				Data.FrontDepthFail = StencilOp::Keep;
				Data.BackEnable = false;
				Data.BackFunc = CompareOp::Always;
				Data.BackPass = StencilOp::Keep;
				Data.BackFail = StencilOp::Keep;
				Data.BackDepthFail = StencilOp::Keep;
				Data.MaskRead = 0xFF;
				Data.MaskWrite = 0xFF;
			}

			DhslInitializer()
			{
				Data.DepthWrite = true;
				Data.DepthFunc = CompareOp::LEQ;
				Data.FrontEnable = false;
				Data.FrontFunc = CompareOp::Always;
				Data.FrontPass = StencilOp::Keep;
				Data.FrontFail = StencilOp::Keep;
				Data.FrontDepthFail = StencilOp::Keep;
				Data.BackEnable = false;
				Data.BackFunc = CompareOp::Always;
				Data.BackPass = StencilOp::Keep;
				Data.BackFail = StencilOp::Keep;
				Data.BackDepthFail = StencilOp::Keep;
				Data.MaskRead = 0xFF;
				Data.MaskWrite = 0xFF;
			}
		};

		public ref class DhslState : ResourceObj
		{
			DEFCLASS(DhslState, ResourceObj, qgDhslState);

		public:
			DhslState(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			DhslData GetData()
			{
				const qbDhslData& u = SELF->GetData();

				DhslData d;
				d.DepthWrite = u.depth_write;
				d.DepthFunc = (CompareOp)u.depth_func;
				d.FrontEnable = u.front_enable;
				d.FrontFunc = (CompareOp)u.front_func;
				d.FrontPass = (StencilOp)u.front_pass;
				d.FrontFail = (StencilOp)u.front_fail;
				d.FrontDepthFail = (StencilOp)u.front_depth_fail;
				d.BackEnable = u.back_enable;
				d.BackFunc = (CompareOp)u.back_func;
				d.BackPass = (StencilOp)u.back_pass;
				d.BackFail = (StencilOp)u.back_fail;
				d.BackDepthFail = (StencilOp)u.back_depth_fail;
				d.MaskRead = u.mask_read;
				d.MaskWrite = u.mask_write;

				return d;
			}
		};


		//////////////////////////////////////////////////////////////////////////
		public enum class ShaderType
		{
			VS,
			PS,
		};

		public enum class ShaderRole
		{
			Manual,
			Auto,
			Discard,
		};

		public enum class ShaderData
		{
			Unknown,
			Float1,
			Float2,
			Float3,
			Float4,
			Float16,
			Int1,
			Int2,
			Int3,
			Int4,
			Byte1,
			Byte2,
			Byte3,
			Byte4,
			Splr1D,
			Splr2D,
			Splr3D,
			SplrCube,
		};

		public enum class ShaderAuto
		{
			OrthoProj,
			World,
			View,
			Proj,
			ViewProj,
			InverseView,
			WorldViewProj,
			Tex0,
			Tex1,
			Tex2,
			Tex3,
			Tex4,
			Tex5,
			Tex6,
			Tex7,
			PropVec0,
			PropVec1,
			PropVec2,
			PropVec3,
			PropMat0,
			PropMat1,
			PropMat2,
			PropMat3,
			MatPalette,
		};

		public ref class Shader : ResourceObj
		{
			DEFCLASS(Shader, ResourceObj, qgShader);

		public:
			Shader(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			bool BindFile(ShaderType type, String^ filename, kint flags)
			{
				array<kbyte>^ bs = Encoding::UTF8->GetBytes(filename);
				pin_ptr<kbyte> pn = &bs[0];
				return SELF->BindFile((qgShaderType)type, (char*)pn, flags);
			}

			bool BindString(ShaderType type, String^ data, int flags)
			{
				array<kbyte>^ bs = Encoding::UTF8->GetBytes(data);
				pin_ptr<kbyte> pn = &bs[0];
				return SELF->BindData((qgShaderType)type, pn, bs->Length, flags);
			}

			bool BindShader(ShaderType type, Shader^ shd)
			{
				return SELF->BindShader((qgShaderType)type, (qgShader*)shd->Handle.ToPointer());
			}

			bool BindShader(ShaderType type, String^ name)
			{
				array<kbyte>^ bs = Encoding::UTF8->GetBytes(name);
				pin_ptr<kbyte> pn = &bs[0];
				return SELF->BindShader((qgShaderType)type, (char*)pn);
			}

			bool Link()
			{
				return SELF->Link();
			}

			property bool HasPixelShader
			{
				bool get()
				{
					return SELF->HasPixelShader();
				}
			}

			property bool HasVertexShader
			{
				bool get()
				{
					return SELF->HasVertexShader();
				}
			}

			void AddCondition(String^ str)
			{
				array<kbyte>^ bs = Encoding::UTF8->GetBytes(str);
				pin_ptr<kbyte> pn = &bs[0];
				SELF->AddCondition((char*)pn);
			}

			bool HasCondition(String^ str)
			{
				array<kbyte>^ bs = Encoding::UTF8->GetBytes(str);
				pin_ptr<kbyte> pn = &bs[0];
				return SELF->HasCondition((char*)pn);
			}

			void ClearConditions()
			{
				SELF->ClearConditions();
			}
		};


		//////////////////////////////////////////////////////////////////////////
		[StructLayout(LayoutKind::Sequential)]
		[Serializable]
		public value struct VertexLayoutElement
		{
		public:
			DloUsage Usage;
			int Index;
			DloType Type;
			int Slot;
			int Insts;

			VertexLayoutElement(DloUsage usage, int index, DloType type, int slot)
			{
				Usage = usage;
				Index = index;
				Type = type;
				Slot = slot;
				Insts = 0;
			}

			VertexLayoutElement(DloUsage usage, int index, DloType type)
			{
				Usage = usage;
				Index = index;
				Type = type;
				Slot = 0;
				Insts = 0;
			}

			VertexLayoutElement(DloUsage usage, DloType type)
			{
				Usage = usage;
				Index = 0;
				Type = type;
				Slot = 0;
				Insts = 0;
			}

			String^ ToString() override
			{
				return String::Format("{0}({1}) {2}({3})", Usage, Index, Type, Slot);
			}
		};

		public ref class VertexLayout : ResourceObj
		{
			DEFCLASS(VertexLayout, ResourceObj, qgVertexLayout);

		public:
			VertexLayout(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			property int Stride
			{
				int get()
				{
					return SELF->GetStride();
				}
			}

			int GetStageStride(int stage)
			{
				return SELF->GetStageStride(stage);
			}
		};


		//////////////////////////////////////////////////////////////////////////
		public enum class DrawBufferType
		{
			Data,
			Index,
			Vertex,
		};

		public ref class DrawBuffer : ResourceObj
		{
			DEFCLASS(DrawBuffer, ResourceObj, qgBuffer);

		public:
			DrawBuffer(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			IntPtr Map(int flags)
			{
				return (IntPtr)SELF->Map(flags);
			}

			IntPtr Map()
			{
				return (IntPtr)SELF->Map();
			}

			bool Unmap()
			{
				return SELF->Unmap();
			}

			property DrawBufferType BufferType
			{
				DrawBufferType get()
				{
					return (DrawBufferType)SELF->GetType();
				}
			}

			property int Stride
			{
				int get()
				{
					return SELF->GetStride();
				}
			}

			property int Size
			{
				int get()
				{
					return SELF->GetSize();
				}
			}

			// bool SetData(kconstpointer data, kint size = 0);
		};


		//////////////////////////////////////////////////////////////////////////
		public ref class DepthBuffer : public ResourceObj
		{
			DEFCLASS(DepthBuffer, ResourceObj, qgDepthBuffer);

		public:
			DepthBuffer(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			property int Width
			{
				int get()
				{
					return (int)SELF->GetWidth();
				}
			}

			property int Height
			{
				int get()
				{
					return (int)SELF->GetHeight();
				}
			}
		};


		//////////////////////////////////////////////////////////////////////////
		public enum class TextureType
		{
			Type1D,
			Type2D,
			Type3D,
			TypeCube,
			Type2DArray,
		};

		public enum class TextureFace
		{
			None,
			PX, NX,
			PY, NY,
			PZ, NZ,
		};

		[Flags]
		public enum class TextureFlag
		{
			NoMip = QGTEXF_NOMIP,
			Array = QGTEXF_ARRAY,
			Image = QGTEXF_IMAGE,
			Motion = QGTEXF_MOTION,
			Alloc = QGTEXF_ALLOC,
			Off = QGTEXF_ALLOC,
		};

		public value struct TextureMap
		{
		public:
			IntPtr Data;
			int Pitch, Slice;
			int Width, Height, Depth;
		};

		public ref class TextureMotion
		{
		private:
			qbTextureMotion* _ptr;

		internal:
			TextureMotion(IntPtr ptr)
				: _ptr((qbTextureMotion*)ptr.ToPointer())
			{
			}

		public:
			property int Count
			{
				int get()
				{
					return _ptr->GetCount();
				}
			}

			property float FixedLength
			{
				void set(float f)
				{
					_ptr->SetFixedLength(f);
				}
			}

			property int Fps
			{
				int get()
				{
					return _ptr->GetFps();
				}
				void set(int n)
				{
					_ptr->SetFps(n);
				}
			}

			property int Index
			{
				int get()
				{
					return _ptr->GetIndex();
				}
			}

			property float Length
			{
				float get()
				{
					return _ptr->GetLength();
				}
			}

			property float Advance
			{
				float get()
				{
					return _ptr->GetAdvance();
				}
			}

			property bool Loop
			{
				bool get()
				{
					return _ptr->IsLoop();
				}
				void set(bool v)
				{
					_ptr->TurnLoop(v);
				}
			}

			property bool Play
			{
				bool get()
				{
					return _ptr->IsPlay();
				}
				void set(bool v)
				{
					_ptr->SetPlayMode(v);
				}
			}

			void SetFrameRange(int min, int max)
			{
				_ptr->SetFrameRange(min, max);
			}

			void SetPosition(float pos)
			{
				_ptr->SetPosition(pos);
			}

			void Reset()
			{
				_ptr->Reset();
			}

			bool MotionUpdate(float adv)
			{
				return _ptr->MotionUpdate(adv);
			}
		};

		public ref class TextureOff
		{
		private:
			qbTextureOff* _ptr;

		internal:
			TextureOff(IntPtr ptr)
				: _ptr((qbTextureOff*)ptr.ToPointer())
			{
			}

		public:
			bool Enter(Clearance clr, ColorValue color, kuint stencil)
			{
				return _ptr->Enter((int)clr, (tpl::ColorValue&)color, stencil);
			}

			bool Enter(Clearance clr, ColorValue color)
			{
				return _ptr->Enter((int)clr, (tpl::ColorValue&)color, 0);
			}

			bool Enter(Clearance clr)
			{
				return _ptr->Enter((int)clr, tpl::ColorValues::Black, 0);
			}

			bool Enter(Clearance clr, kuint stencil)
			{
				return _ptr->Enter((int)clr, tpl::ColorValues::Black, stencil);
			}

			bool Leave()
			{
				return _ptr->Leave();
			}
		};

		public ref class Texture : ResourceObj
		{
			DEFCLASS(RaszState, ResourceObj, qgTexture);

		public:
			Texture(IntPtr handle)
				: super_type(handle)
			{
			}

		public:
			bool Map([Out] TextureMap% map, int flags, int mip, int sliceface)
			{
				qbTextureMap m;
				bool ret = SELF->Map(&m, flags, mip, sliceface);
				if (!ret)
					return false;
				else
				{
					map = MapToMap(m);
					return true;
				}
			}

			bool Map([Out] TextureMap% map, int flags, int mip)
			{
				qbTextureMap m;
				bool ret = SELF->Map(&m, flags, mip, 0);
				if (!ret)
					return false;
				else
				{
					map = MapToMap(m);
					return true;
				}
			}

			bool Map([Out] TextureMap% map, int flags)
			{
				qbTextureMap m;
				bool ret = SELF->Map(&m, flags, 0, 0);
				if (!ret)
					return false;
				else
				{
					map = MapToMap(m);
					return true;
				}
			}

			bool Unmap()
			{
				return SELF->Unmap();
			}

			TextureMotion^ GetMotion()
			{
				qbTextureMotion* p = SELF->GetMotion();
				return p == NULL ? nullptr : gcnew TextureMotion((IntPtr)p);
			}

			TextureOff^ GetOff()
			{
				qbTextureOff* p = SELF->GetOff();
				return p == NULL ? nullptr : gcnew TextureOff((IntPtr)p);
			}

			property SbCli::Qgp::TextureType TextureType
			{
				SbCli::Qgp::TextureType get()
				{
					return (SbCli::Qgp::TextureType)SELF->GetType();
				}
			}

			property SbCli::Qgp::ColorFormat ColorFormat
			{
				SbCli::Qgp::ColorFormat get()
				{
					return (SbCli::Qgp::ColorFormat)SELF->GetColorFormat();
				}
			}

			property int Width
			{
				int get()
				{
					return SELF->GetWidth();
				}
			}

			property int Height
			{
				int get()
				{
					return SELF->GetHeight();
				}
			}

			property int Depth
			{
				int get()
				{
					return SELF->GetDepth();
				}
			}

			property int MipCount
			{
				int get()
				{
					return SELF->GetMipCount();
				}
			}

			property bool HasAlpha
			{
				bool get()
				{
					return SELF->HasAlpha();
				}
			}

			property bool HasMips
			{
				bool get()
				{
					return SELF->HasMips();
				}
			}

			property bool IsMotion
			{
				bool get()
				{
					return SELF->IsMotion();
				}
			}

			property bool IsOff
			{
				bool get()
				{
					return SELF->IsOff();
				}
			}

		private:
			static TextureMap MapToMap(qbTextureMap& m)
			{
				TextureMap map;
				map.Data = (IntPtr)m.data;
				map.Pitch = m.pitch;
				map.Slice = m.slice;
				map.Width = m.width;
				map.Height = m.height;
				map.Depth = m.depth;
				return map;
			}
		};
	}
}
